package tests;


import java.io.*; 

import global.*;
import bitmap.BitMapFile;
import bitmap.InstantiateColumnarFile;
import bitmap.KeyClass;
import btree.BTreeFile;
import btree.IntegerKey;
import bufmgr.*;
import diskmgr.*;
import heap.*;
import iterator.*;
import index.*;

import java.util.ArrayList;
import java.util.Random;
import java.util.StringTokenizer;

import columnar.ColumnarFileInfo;
import columnar.Columnarfile;
import columnar.TupleScan;
import iterator.NestedLoopsJoins;



public class NestedJoinTest {
	
	private static BitMapFile bmf = null;	
	private static BTreeFile btf=null;
	
	private static String Outerdatafile,Innerdatafile;
	private static String OutercolumnDbName, InnercolumnDbName;
	private static String OutercolumnarFileName, InnercolumnarFileName;
	
	private static ArrayList <String> OutercolumnNames=new ArrayList<String>();
	private static ArrayList <String> InnercolumnNames=new ArrayList<String>();
	private static int[]OOutIndex, IOutIndex;
	
	
	private static String accessType;
	private static String valueConstraint;
	private static String numBuf;
	
	private static String columnName[];
	private static int operator[];
	private static String columnValue[];
	private static KeyClass value[];
	
	private static  int OutercolumnIndex[];
	private static	int InnercolumnIndex[];
	
	private static int columnAbsoluteIndex=0;
	
	private static Columnarfile Outerfile, Innerfile = null;
	private static AttrType[] Outertypes;
	private static AttrType[] Innertypes;
	private static int startRead = 0, startWrite = 0;
	
	private static String []OutercolNames;
	private static String []InnercolNames;
	private static String []ANDOR;
	
	private static short []Rsizes,Ssizes;
	private static int n_out_flds;
	private static FldSpec[] proj_list;
	
	
	
	
	
		public static boolean isInteger( String input )  
		 {  
		    try  
		    {  
		       Integer.parseInt( input );  
		       return true;  
		    }  
		    catch( Exception e)  
		    {  
		       return false;  
		    }  
		} 
		
		public static void parseValue(String tempValue,int maxIndex)
		{
			//Parsing the condition expressions
		    OutercolumnIndex=new int[maxIndex];
			InnercolumnIndex=new int[maxIndex];	
			columnName=new String[maxIndex];
			columnValue= new String[maxIndex];
			operator= new int[maxIndex];
			
			
			StringTokenizer st = new StringTokenizer(tempValue, ":");
			System.out.println("0..."+tempValue);
			int i=0;
			while(st.hasMoreElements())
			{	
			
				InnercolumnIndex[i]=1;
				OutercolumnIndex[i]=1;
			//	value[i]=null;
				columnName[i]=st.nextToken();

				System.out.println(OutercolNames);
				System.out.println(InnercolNames);
				
				System.out.println("1..."+columnName[i]);
				
			System.out.println("1..."+columnName[i]);
			for(String str: OutercolNames)
			{
				if(str.equalsIgnoreCase(columnName[i]))
					break;
				OutercolumnIndex[i]++;
				System.out.println("Outer"+OutercolumnIndex[i]);
			}
			
			operator[i]=getOperator(st.nextToken());
			System.out.println("1..."+operator[i]);
			columnValue[i]=st.nextToken();
			System.out.println("2..."+columnValue[i]); // The second operand..
			
			for(String str: InnercolNames)
			{
				if(str.equalsIgnoreCase(columnValue[i]))
					break;
				InnercolumnIndex[i]++;
				System.out.println("Inner"+InnercolumnIndex[i]);
			}
		
			/*try  
		    {  
		       Integer.parseInt( columnValue[i] );  
		       value[i]=InstantiateColumnarFile.setKeyClass(value[i], 0, columnValue[i]);
		    }  
		    catch( Exception e)  
		    {  
		    	
		    	if(containscol(columnValue[i],))
		    	value[i]=InstantiateColumnarFile.setKeyClass(value[i], 1, columnValue[i]);
		    }
		    

		    
		    System.out.println(value[i]);*/
		    i++;
		    
			}
		}
	  
	public static void main(String args[])
	{
		

		/*types[0] = new AttrType(AttrType.attrString);
		types[1] = new AttrType(AttrType.attrString);
		types[2] = new AttrType(AttrType.attrInteger);
		types[3] = new AttrType(AttrType.attrInteger);*/
		startRead = pcounter.rcounter;
		startWrite = pcounter.wcounter;
		Outertypes= new AttrType[4];
		Innertypes= new AttrType[4];
		

		
		Rsizes= new short[4];
		Ssizes= new short[4];
	  int maxIndex=0;
        Outerdatafile=args[1];	  
	  
		OutercolumnDbName=args[2];

		OutercolumnarFileName=args[3];
		//System.out.println(OutercolumnDbName+" "+OutercolumnarFileName);
		
		Innerdatafile=args[4];
		InnercolumnDbName=args[5];
		InnercolumnarFileName=args[6];
		//System.out.println(InnercolumnDbName+" "+InnercolumnarFileName);		
		
		accessType=args[args.length-1]; //for outer
		numBuf=args[args.length-2];
		
		valueConstraint=args[args.length-3]; //should be the next string after WHERE
	      // System.out.println(valueConstraint);
	       //System.out.println(args[5]);
	       String filepath = "/home/apurva/workspace/aks_db/src/tests/";
		//Output Fields.
	     try
	     { 
			FileInputStream fin1 = new FileInputStream(filepath+Outerdatafile);
			DataInputStream din1 = new DataInputStream(fin1);
			BufferedReader bin1 = new BufferedReader(new InputStreamReader(din1));
			
		
			
			/* code that reads first line, reads schema and creates Columnarfile */
			String line = bin1.readLine();
		 
			StringTokenizer st = new StringTokenizer(line);
			int i = 0, tuplelength1 = 0;
			while(st.hasMoreTokens())	
			{	
				 //  System.out.println(line);
				String argToken = st.nextToken();
				StringTokenizer temp = new StringTokenizer(argToken);
				
				String tokenParts1 = temp.nextToken(":");
				String tokenParts2 = temp.nextToken(":");
				//System.out.println(tokenParts1);
				//OutercolNames[i] = tokenParts1;
				//System.out.println("Outer column"+OutercolNames[i]);
				if (tokenParts2.equals("int"))
				{
					Outertypes[i] = new AttrType(AttrType.attrInteger);
					Rsizes[i]=0;
					tuplelength1 = tuplelength1 + 4;
				}
				else {
					Outertypes[i] = new AttrType(AttrType.attrString);
					Rsizes[i]=25;
					StringTokenizer temp1 = new StringTokenizer(tokenParts2);
					
					temp1.nextToken("(");
					String dummy = temp1.nextToken("(");
					temp1 = null; 
					temp1 =	new StringTokenizer(dummy);
					String dummy1 = temp1.nextToken(")"); 
					Size.STRINGSIZE = Integer.parseInt(dummy1);
					System.out.println("size: "+ Size.STRINGSIZE);
					tuplelength1 = tuplelength1 + Size.STRINGSIZE;
				}
				i++;		
			}
	     }
	     catch(Exception e){
	    	 e.printStackTrace();
	    	 
	     }
		
	     //For inner file....
		try{
	     FileInputStream fin2 = new FileInputStream(filepath+Innerdatafile);
			DataInputStream din2 = new DataInputStream(fin2);
			BufferedReader bin2 = new BufferedReader(new InputStreamReader(din2));
			
		
			
			/* code that reads first line, reads schema and creates Columnarfile */
			String line1 = bin2.readLine();
		
			StringTokenizer st1 = new StringTokenizer(line1);
			int k = 0, tuplelength2 = 0;
			while(st1.hasMoreTokens())	
			{	
				String argToken = st1.nextToken();
				StringTokenizer temp = new StringTokenizer(argToken);
				
				String tokenParts1 = temp.nextToken(":");
				String tokenParts2 = temp.nextToken(":");
				
				//InnercolNames[k] = tokenParts1;
				//System.out.println(InnercolNames[k]);
				if (tokenParts2.equals("int"))
				{
					Innertypes[k] = new AttrType(AttrType.attrInteger);
					Ssizes[k]=0;
					tuplelength2 = tuplelength2 + 4;
				}
				else {
					Innertypes[k] = new AttrType(AttrType.attrString);
					Ssizes[k]=25;
					StringTokenizer temp1 = new StringTokenizer(tokenParts2);
					
					temp1.nextToken("(");
					String dummy = temp1.nextToken("(");
					temp1 = null; 
					temp1 =	new StringTokenizer(dummy);
					String dummy1 = temp1.nextToken(")"); 
					Size.STRINGSIZE = Integer.parseInt(dummy1);
					System.out.println("size: "+ Size.STRINGSIZE);
					tuplelength2 = tuplelength2 + Size.STRINGSIZE;
				}
				k++;		
			}
		}catch(Exception e){}
		
			for(int m=0;m<Outertypes.length;m++)
			{
				System.out.println("Outer types and string sizes "+Outertypes[m]+" "+Rsizes[m]+" Inner types and string sizes "+Innertypes[m]+" "+Ssizes[m]);
				
			}
		

/*	          
		Outertypes= new AttrType[4];
		 Outertypes[0] = new AttrType(AttrType.attrString);
			Outertypes[1] = new AttrType(AttrType.attrString);
			Outertypes[2] = new AttrType(AttrType.attrInteger);
			Outertypes[3] = new AttrType(AttrType.attrInteger);

			Innertypes= new AttrType[4];
			
			 Innertypes[0] = new AttrType(AttrType.attrString);
				Innertypes[1] = new AttrType(AttrType.attrString);
				Innertypes[2] = new AttrType(AttrType.attrInteger);
				Innertypes[3] = new AttrType(AttrType.attrInteger);*/

			//	Innerfile= new Columnarfile(InnercolumnarFileName,4,Innertypes);
			
		//Store the column attr types.

		
		
		SystemDefs sysdef = new SystemDefs(OutercolumnDbName,100000,Integer.parseInt(numBuf),"Clock");
		ColumnarFileInfo cInfo = new  ColumnarFileInfo(OutercolumnarFileName+".hdr");
		Outerfile=new Columnarfile(OutercolumnarFileName, 4, Outertypes);
		cInfo = Outerfile.getColumnarFileInfo(OutercolumnarFileName+".hdr");
		OutercolNames = cInfo.getColumnNames();

		
		
		SystemDefs sysdef1 = new SystemDefs(InnercolumnDbName,100000,Integer.parseInt(numBuf),"Clock");
		ColumnarFileInfo cInfo1 = new  ColumnarFileInfo(InnercolumnarFileName+".hdr");
		Innerfile=new Columnarfile(InnercolumnarFileName, 4, Innertypes);
		cInfo1 = Innerfile.getColumnarFileInfo(InnercolumnarFileName+".hdr");
		InnercolNames = cInfo1.getColumnNames();
		
		
		//All the columns present in the relation
		Outerfile.setColumnNames(OutercolNames);
		Innerfile.setColumnNames(InnercolNames);
		
		int n=7,in=0,on=0,oindex=0;
		   while(!args[n].equals("WHERE"))
		      {  
			   
			   //check which relations column is to be printed 
			   if(args[n].contains("outer"))
			   {  
                     System.out.println(args[n]);
				  // String[] splitarr= new String[args[n].length()];
				  // splitarr= args[n].split(".");
				   //System.out.println(splitarr[0]);

				   OutercolumnNames.add(args[n]);
			       on++;
			   }
			   if(args[n].contains("inner"))
				   
				   {
				   //String[] splitarr1=args[n].split(".");
				   InnercolumnNames.add(args[n]);
				       in++;
				   }
				//maxIndex++;
				  //System.out.println("Output columns "+args[i]);
				  n++;	oindex++;
		      }
		   
		   OOutIndex=new int[on];
		   IOutIndex=new int[in];
	
		   int l=0,h=0;
		   while(l<OOutIndex.length)
		   {
			   OOutIndex[l]=getIndex(OutercolumnNames.get(l),OutercolNames)+1;
		       System.out.println("Outer index "+OOutIndex[l]);
			   l++;
			   
		   }
		   
		   while(h<IOutIndex.length)
		   {
			   IOutIndex[h]=getIndex(InnercolumnNames.get(h),InnercolNames)+1;
		       System.out.println("Inner index "+IOutIndex[h]);
			   h++;
			   
		   }
		  
		   
		//Splitting up the conditions
		
		


			
		   StringTokenizer st3 = new StringTokenizer(valueConstraint,"&");
		//int i=0;
		 System.out.println("Max index"+maxIndex);
		while(st3.hasMoreElements())
			
		{
			maxIndex=st3.countTokens();
		parseValue(st3.nextToken(),maxIndex); //Parse the condition expression

		//ANDOR[i++]=st1.nextToken(); // The ith element of this array will follow the ith condition expr.
		
		}
		System.out.println("Max Index"+maxIndex);
		
		// Store values in OutFilter 
		CondExpr[] OutFilter = new CondExpr[maxIndex]; //number of predicates specified in the condition.
		
		for(int p=0;p<OutFilter.length;p++)
		{
		    OutFilter[p]= new CondExpr();	
			OutFilter[p].next  = null;
			OutFilter[p].op    = new AttrOperator(operator[p]);
			AttrType OpType1 = Outerfile.getAttributeTypeForColumname(columnName[p]);
			
			OutFilter[p].type1 = new AttrType(AttrType.attrSymbol);
			
			//if(containscol(columnValue[k].toString(),InnercolNames))
			//{
				OutFilter[p].type2 = new AttrType(AttrType.attrSymbol);
				
			//}
			/*else
		    { if(isInteger(columnValue[k].toString()))
		     {
		    	OutFilter[k].type2 = new AttrType(AttrType.attrInteger);
		    			    	
		     } 
		     else
		    	OutFilter[k].type2 = new AttrType(AttrType.attrString);*/
			
		    //}
				
				OutFilter[p].operand1.symbol =	 new FldSpec(new RelSpec(RelSpec.outer),OutercolumnIndex[p]);	
			OutFilter[p].operand1.string = columnName[p];
			
			OutFilter[p].operand2.symbol =	 new FldSpec(new RelSpec(RelSpec.innerRel),InnercolumnIndex[p]);
			OutFilter[p].operand2.string = columnValue[p];
		    
			
			
		}
		// Assigning length of string fields..
		/*Rsizes= new short[4];
		Rsizes[0]=25;
		Rsizes[1]=25;
		Rsizes[2]=0;
		Rsizes[3]=0;

		Ssizes= new short[4];
		Ssizes[0]=25;
		Ssizes[1]=25;
		Ssizes[2]=0;
		Ssizes[3]=0;*/
		
		n_out_flds= Outerfile.getnumColumns();
		
		proj_list=new FldSpec[oindex];// Fields to be displayed in the output....
		
		int q=0,proj_index=0;
		while(q < OutercolumnNames.size())
		{	
		
		proj_list[proj_index++]= new FldSpec(new RelSpec(RelSpec.outer),OOutIndex[q]);
		q++;
		}
		int m=0;
		while(m< InnercolumnNames.size())
		{	
		
		proj_list[proj_index++]= new FldSpec(new RelSpec(RelSpec.innerRel),IOutIndex[m]);
		m++;
		}
		
		 FldSpec [] Sprojection = {
			       new FldSpec(new RelSpec(RelSpec.outer), 1),
			       new FldSpec(new RelSpec(RelSpec.outer), 2)
			       };
		 
		 //Iterator am= new ColumnarFileScan(Outerfile.getFilename(),Outertypes,Rsizes,(short)3,3,Sprojection,null); 
		 TupleScan outer_am = new TupleScan(Outerfile);
		 try
		 {
		 ColumnarNestedLoopsJoins nlj= new ColumnarNestedLoopsJoins(Outertypes, Outerfile.getnumColumns(), Rsizes,
				  Innertypes, 4, Ssizes,
				  Integer.parseInt(numBuf),
				  outer_am,Innerfile.getFilename(),
				  OutFilter, null, proj_list, oindex,InnercolumnIndex,OutercolumnIndex);
		 Tuple t;
		 while((t = nlj.get_next())!=null)
		 {
			 t.print(Innertypes);
		 }
		 }
		 catch(Exception e)
		 {
			 
			 e.printStackTrace();
		 }
		
		
		 
	}
	
	public static int getIndex(String name, String[] array)
	{
		int index=0;
		for(int i=0;i<array.length;i++)
		{
			if(name.contains(array[i]))
			index=i;
		
			
		}
		
		return index;
		
	}
	public static boolean containscol(String name, String[] colArray)
	{
		for(String element: colArray)
		{
			if (element.equals(name))
			return true;
		}
		
		return false;
	}
	
	
	public static int getOperator(String op)
	{
		System.out.println("Operator is "+op);
		if(op.equals("="))
		      return AttrOperator.aopEQ;
		else
			if(op.equals("<"))
		      return AttrOperator.aopLT;
			else
		    if(op.equals(">"))
		      return AttrOperator.aopGT;
		    else
		    if(op.equals("!="))
		      return AttrOperator.aopNE;
		    else
		    	
		    if(op.equals("<="))
		      return AttrOperator.aopLE;
		    else
		    	if(op.equals(">="))
		      return AttrOperator.aopGE;
		    /*case aopNOT:
		      return "aopNOT";
		    case aopNOP:
		      return "aopNOP";
		    case opRANGE:
		      return "opRANGE";*/
		    	else
		    return -1;
		 	
		
	}
	
	
	
}
